<?php
abstract class ModelFormHelper
{
    protected $availableFields = array();
    private $fields = array();
    private $relations = array();
    protected $tableEntity = null;
    protected $controls = array();
    private $controlMap = array();
    private $events = array("FieldBinding", "FieldBound",
        "FieldRelationBinding");
    private $beforeFormHelpers = array();
    private $afterFormHelpers = array();
    protected $observers = array();
    public function  __construct(Doctrine_Table $entity)
    {
        $this->tableEntity = $entity;
        $this->GetFieldsFromEntity();
        $this->GetRelationships();
    }
    public function getTableObject()
    {
        return $this->tableEntity;
    }
    public function addBeforeFormHelper(ModelFormHelper $formHelper)
    {
        $this->beforeFormHelpers[] = $formHelper;
    }
    public function addAfterFormHelper(ModelFormHelper $formHelper)
    {
        $this->afterFormHelpers[] = $formHelper;
    }
    public function __set($name, $value)
    {
        if(in_array($name, $this->events))
        {
            $this->observers[$name] = $value;
        }
    }
    public function setAvailableFields($fields)
    {
        if(is_array($fields))
        {
            $this->availableFields = $fields;
        }
    }
    public function getAvailableFields()
    {
        return $this->availableFields;
    }
    private function GetFieldsFromEntity()
    {
        if($this->tableEntity != null)
        {
            $this->fields = $this->tableEntity->getColumns();
        }
    }
    private function StartFieldBinding()
    {
        if(!empty ($this->beforeFormHelpers))
        {
            $this->loadExternalControls($this->beforeFormHelpers);
        }
        foreach($this->fields as $field=>$props)
        {
            $fieldName = strtolower($field);
            if(in_array($fieldName, $this->availableFields))
            {
                $relationInfo = $this->GetRelationFieldInfo($fieldName);
                if($relationInfo != null)
                {
                    $props["type"] = "select";
                    $props["isRelationField"] = true;
                    $props["foreignTable"] = $relationInfo["entity"];
                    $props["foreignField"] = $relationInfo["foreignField"];
                    if(isset($this->observers["FieldRelationBinding"]))
                    {
                        $eventArgs = new FieldRelationBindignEventArgs();
                        $eventArgs->fieldName = $fieldName;
                        $eventArgs->fieldProps = $props;
                        call_user_func($this->observers["FieldRelationBinding"],
                            $this, $eventArgs);
                        if(!$eventArgs->IsCancelled())
                        {
                            $props["type"] = $eventArgs->GetType();
                            $props["fieldValue"] = $eventArgs->fieldValue;
                            $props["fieldText"] = $eventArgs->fieldText;
                            $props["dataSource"] = $eventArgs->dataSource;
                        }
                        else
                            $props = array();
                    }
                }
                else if(isset($this->observers["FieldBinding"]))
                {
                    $eventArgs = new FieldBindingEventArgs();
                    $eventArgs->fieldName = $fieldName;
                    $eventArgs->fieldProps = $props;
                    call_user_func($this->observers["FieldBinding"],
                        $this, $eventArgs);
                    $props = $eventArgs->fieldProps;
                }
                if(!empty ($props))
                {
                    $control = FieldBuilder::Build($fieldName, $props);
                    if(isset($this->observers["FieldBound"]))
                    {
                        call_user_func($this->observers["FieldBound"],
                            $control, $fieldName);
                    }
                    $this->controls[] = $control;
                    $this->controlMap["$fieldName"] = array("control" => $control,
                        "isExternal" => false, "table" => $this->tableEntity);
                }
            }
        }
         if(!empty ($this->afterFormHelpers))
        {
            $this->loadExternalControls($this->afterFormHelpers);
        }
    }
    private function loadExternalControls($source)
    {
        foreach($source as $formHelper)
        {
            $externalControls = $formHelper->getControlFields();
            foreach($externalControls as $control)
            {
                $this->controls[] = $control;
                $this->controlMap[$control->getname()] = array("control" => $control,
                    "isExternal" => true,
                    "table" => $formHelper->getTableObject() );
            }
        }
    }
    protected function GetRelationFieldInfo($fieldName)
    {
        foreach($this->relations as $relation)
        {
            if($relation["localField"] == $fieldName)
                return $relation;
        }
        return null;
    }
    private function GetRelationships()
    {
        $relationships = $this->tableEntity->getRelations();
        foreach( $relationships as $relationship )
        {
            $conditional = $relationship->getCondition();
            $parts = explode('.', $conditional);
            $relation["entity"] = $this->tableEntity
                    ->getRelation($parts[0])->getClass();
            $relation["localField"] = $this->tableEntity
                    ->getRelation($parts[0])->getLocal();
            $relation["foreignField"] = $this->tableEntity
                    ->getRelation($parts[0])->getForeign();
            $this->relations[] = $relation;
        }
    }
    public function getControlFields()
    {
        $this->StartFieldBinding();
        return $this->controls;
    }
    abstract public function save();
}
?>